﻿#include "VulkanMaterial.h"

#include "Render/VulkanContext.h"
#include "Render/Texture/VulkanTexture2D.h"
#include "Render/Texture/VulkanTextureCube.h"

bool CVulkanMaterial::CanDefferRender()
{
    return Pipeline->Type == ERenderMaterialType::Opaque;
}

bool CVulkanMaterial::CanUnlitRender()
{
    return Pipeline->Type == ERenderMaterialType::Unlit;
}

void CVulkanMaterial::PrepareSelfRecord()
{
    SVulkanDescriptorPoolSize PoolSize;
    PoolSize.SetNum=1;
    PoolSize.DescriptorNums.CombinedImageSamplerDescriptorNum=Parameters->Texture2Ds.Num() + Parameters->TextureCubes.Num();
    PoolSize.DescriptorNums.UniformBufferDescriptorNum=Parameters->FloatParameterBuffer.GetSize()>0?1:0;
    CVulkanContext::Get()->GetAutoResetDescriptorPool()->MaterialPool.PoolSize+=PoolSize;

}

void CVulkanMaterial::MakeSureDescriptorSetAvaliable()
{
    // if(LastFrame == CVulkanContext::Get()->CurrentFrame)
    // {
    //     //这一帧已经更新过了
    //     return;
    // }
    // LastFrame=CVulkanContext::Get()->CurrentFrame;

    if(DescriptorSet)
    {
        return;
    }

    //创建描述符集，由于描述符池自动重置，所以每帧都要重新分配描述符
    {
        TVector<vk::DescriptorSetLayout> DescriptorSetLayouts = { Pipeline->DescriptorSetLayout };

        vk::DescriptorSetAllocateInfo DescriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo()
        .setDescriptorPool(CVulkanContext::Get()->GetAutoResetDescriptorPool()->MaterialPool.Pool)
        .setSetLayouts(DescriptorSetLayouts);            

        DescriptorSet = CVulkanContext::Get()->GetDevice().allocateDescriptorSets(DescriptorSetAllocateInfo)[0];
    }

    //写入描述符
    {
        TVector<vk::WriteDescriptorSet> WriteDescriptorSets;

        int32_t CurrentBindingIndex = 0;
        TVector<vk::DescriptorImageInfo> DescriptorTexture2DInfos;
        if(!Parameters->Texture2Ds.Empty())
        {
            for (int32_t i = 0; i < Parameters->Texture2Ds.Num(); i++)
            {
                DescriptorTexture2DInfos.Add(vk::DescriptorImageInfo()
                    .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
                    .setImageView(Parameters->Texture2Ds[i]->ImageView)
                    .setSampler(CVulkanContext::Get()->GetDefaultImageSampler()));
            }

            WriteDescriptorSets.Add(vk::WriteDescriptorSet()
                .setDstSet(DescriptorSet)
                .setDstBinding(CurrentBindingIndex)
                .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
                .setDescriptorCount(DescriptorTexture2DInfos.Num())
                .setPImageInfo(DescriptorTexture2DInfos.Data())
                .setDstArrayElement(0));
            
            CurrentBindingIndex++;         
        }

        TVector<vk::DescriptorImageInfo> DescriptorTextureCubeImageInfos;
        if(!Parameters->TextureCubes.Empty())
        {
            for (int32_t i = 0; i < Parameters->TextureCubes.Num(); i++)
            {
                DescriptorTextureCubeImageInfos.Add(vk::DescriptorImageInfo()
                    .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
                    .setImageView(Parameters->TextureCubes[i]->ImageView)
                    .setSampler(Parameters->TextureCubes[i]->Sampler));
            }

            WriteDescriptorSets.Add(vk::WriteDescriptorSet()
                .setDstSet(DescriptorSet)
                .setDstBinding(CurrentBindingIndex)
                .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
                .setDescriptorCount(DescriptorTextureCubeImageInfos.Num())
                .setPImageInfo(DescriptorTextureCubeImageInfos.Data())
                .setDstArrayElement(0));
            
            CurrentBindingIndex++;         
        }

        vk::DescriptorBufferInfo DescriptorBufferInfo = vk::DescriptorBufferInfo()
        .setBuffer(Parameters->FloatParameterBuffer.GetBuffer())
        .setOffset(0)
        .setRange(Parameters->FloatParameterBuffer.GetSize());
        if(Parameters->FloatParameterBuffer.GetSize()>0)
        {

            WriteDescriptorSets.Add(vk::WriteDescriptorSet()
                .setDstSet(DescriptorSet)
                .setDstBinding(CurrentBindingIndex)
                .setDescriptorType(vk::DescriptorType::eUniformBuffer)
                .setDescriptorCount(1)
                .setPBufferInfo(&DescriptorBufferInfo)
                .setDstArrayElement(0));
            
            CurrentBindingIndex++;
        }

        CVulkanContext::Get()->GetDevice().updateDescriptorSets(WriteDescriptorSets, nullptr);

    }
}